import axios from 'axios'
import router from '@/router'
import { LOGIN_URL } from '@/common/constants/global'
import { useLoading } from '@/hooks/useLoading'
import { useAuthStore } from '@/stores/auth'
import { useUserStore } from '@/stores/user'
import { ElMessage, ElMessageBox } from 'element-plus'
import { RequestController } from './requestController'

// 创建 axios 实例
const service = axios.create({
  // 默认地址请求地址，可在 .env.** 文件中修改
  baseURL: import.meta.env.VITE_API_URL, // 基础路径
  // 设置超时时间
  timeout: 60000,
  // 跨域时候允许携带凭证
  withCredentials: true,
  // 请求头
  headers: { 'Content-Type': 'application/json;charset=utf-8' }
})

// 请求终止器
const requestController = new RequestController()

/**
 * 请求拦截器
 * @prop {Object} config 配置项
 * @property {Boolean} config.norepeat 是否禁止重复请求，默认true
 * @property {Boolean} config.loading 是否显示全局loading，默认true
 * @property {Boolean} config.filter 是否过滤掉载荷中值为 空字符串 | null | undefined 的字段，默认false
 */
service.interceptors.request.use(
  (config) => {
    const authStore = useAuthStore()

    // norepeat：是否禁止重复请求，默认true
    config.norepeat ??= true
    config.norepeat && requestController.addPending(config)

    // loading：是否显示全局loading，默认true
    config.loading ??= true
    config.loading && useLoading().open()

    // filter: 是否过滤掉载荷中值为 空字符串 | null | undefined 的字段，默认false
    config.filter ??= false
    if (config.filter && config.method === 'post') {
      const payload = typeof config.data === 'object' ? config.data : JSON.parse(config.data)
      Object.keys(payload).forEach((key) => {
        if (payload[key] === '' || payload[key] === null || payload[key] === undefined) delete payload[key]
      })
      config.data = JSON.stringify(payload)
    }

    // token访问令牌添加
    config.headers.Authorization = 'Bearer ' + authStore.access_token

    return config
  },
  (error) => {
    return Promise.reject(error)
  }
)

/**
 * 响应拦截器
 */
service.interceptors.response.use(
  async (response) => {
    const { data, config } = response

    // 关闭loading
    config.loading && useLoading().close()
    requestController.removePending(config)

    // 响应守卫
    const next = await responseGuard(response)
    if (!next) return Promise.reject(data)

    // 成功请求
    return data
  },
  async (error) => {
    const { config, response, message, name } = error

    // 关闭loading
    config.loading && useLoading().close()

    // 报错信息处理
    if (response) {
      // 响应守卫
      const next = await responseGuard(response)
      if (next && next?.data) return next.data
    } else if (message) {
      // 请求取消处理
      if (name == 'CanceledError') return Promise.reject(name)
      /**
       * 系统级报错信息
       * 区别于responseGuard中报错提示
       * 此属特殊情况下无response响应体时特殊情况
       */
      ElMessage.error(message)
    }

    // 断网处理：跳转500页面
    if (!window.navigator.onLine) router.replace('/500')

    return Promise.reject(error)
  }
)

/**
 * 响应守卫
 * @description 处理响应数据
 * @param {Response} response 响应体
 * @returns {Boolean | Promise<Boolean> | Promise<Response>} 是否通过
 */
let msgboxSingle = false // 登录对话框单例标志
async function responseGuard(response) {
  // 请求配置项
  const config = response.config
  // http状态码
  const code = response?.data.code || response?.data.statusCode || response?.status
  // 信息消息
  const msg = response?.data.msg || response?.data.errMsg || response?.data.message || response.statusText

  const authStore = useAuthStore()
  const userStore = useUserStore()

  if (code == 401) {
    // access_token 过期，需要静默无感刷新
    if (msg == 'jwt expired') {
      // 需要先暂停请求
      requestController.pausePending(config)
      // 刷新token后，再恢复请求
      await authStore.refreshTokenSilence()
      // 更新token后恢复请求
      config.headers.Authorization = 'Bearer ' + authStore.access_token
      const resumeRes = await requestController.resumePending(config)
      return resumeRes
    }

    // 登录对话框需要单例
    if (!msgboxSingle) {
      msgboxSingle = true
      ElMessageBox.confirm(msg, '系统警告', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        authStore.clearToken()
        userStore.clearUserInfo()
        router.replace(LOGIN_URL)
        msgboxSingle = false
      })
    }

    return false
  }

  // 错误页面主动跳转
  if (code == 403 || code == 404 || (code == 500 && AUTO_SKIP_ERROR_PAGE)) {
    router.push(`/${code}`)
    ElMessage({
      type: 'error',
      message: msg,
      grouping: true
    })
    return false
  }

  // 非 200 系状态码
  if (!String(code)?.startsWith('2')) {
    let msgText = msg

    // 数组形式使用富文本
    let useHTMLString = Array.isArray(msgText)
    if (useHTMLString) msgText = msgText.join('<br/>')
    /**
     * 错误信息提示
     * 可能存在数组形式，需要以html格式并换行显示
     */
    ElMessage({
      type: 'error',
      message: msgText,
      dangerouslyUseHTMLString: useHTMLString, // 按需开启
      grouping: true
    })
    return false
  }

  return true
}

export default service
